use regex::Regex;
use serde::{Deserialize, Serialize};
use serde_json::{json, Map, Value};
use std::io::Read;

#[derive(Deserialize, Serialize, Debug)]
pub struct Config {
    pub name: String,
    pub config_path: String,
    config: Map<String, Value>,
}

impl Config {
    pub fn new(config_name: &str) -> Config {
        Config {
            name: config_name.to_string(),
            config_path: "".to_string(),
            config: Map::new(),
        }
    }

    ///根据文件路径新建配置
    pub fn new_by_path(path: &String) -> Config {
        //判断文件是否存在
        if !std::path::Path::new(path).exists() {
            return Config::new("");
        }
        let str = get_json_str(path);
        match serde_json::from_str(&str) {
            Ok(config) => config,
            Err(_) => Config::new(""),
        }
    }

    ///根据csv文件路径初始化所有配置
    pub fn init_by_csv_paths(&mut self, paths: Vec<String>, config_path: &str) {
        let mut path_index = 0;
        for path in paths {
            path_index += 1;
            self.push_config(path_index, path.clone());

            let path = config_path.to_string() + &path;
            //打开csv文件
            let csv_buf = std::fs::File::open(&path).unwrap();
            let mut rdr = csv::ReaderBuilder::new()
                .comment(Some(b'#'))
                .from_reader(csv_buf);
            match rdr.headers() {
                Err(_) => {
                    println!("文件,{},解析失败", &path);
                }
                Ok(headers) => {
                    headers
                        .into_iter()
                        .filter(|header| !header.is_empty())
                        .enumerate()
                        .for_each(|(_, header)| {
                            self.push_config_types(
                                path_index.to_string(),
                                header.to_string(),
                                "".to_string(),
                            );
                        });
                }
            }
        }
    }

    ///新建配置item
    pub fn new_item(index: u16, table_name: String) -> Map<String, Value> {
        let mut map = Map::new();
        map.insert("index".into(), Value::Number(index.into()));
        map.insert("is_client".into(), Value::Bool(true));
        map.insert("table_name".into(), Value::String(table_name));
        map.insert("json_name".into(), Value::String("".into()));
        map.insert("types".into(), Value::Object(Map::<String, Value>::new()));
        map
    }

    /// 添加配置
    pub fn push_config(&mut self, index: u16, table_name: String) {
        if let None = self.config.get(&index.to_string()) {
            self.config.insert(
                index.to_string(),
                Value::Object(Config::new_item(index, table_name.clone())),
            );
        }
    }

    /// 添加配置字段类型
    pub fn push_config_types(&mut self, index: String, key: String, type_name: String) {
        if let Value::Object(item_typs) = self
            .config
            .get_mut(&index)
            .unwrap()
            .get_mut("types")
            .unwrap()
        {
            if key.is_empty() {
                return;
            }
            match item_typs.get_mut(&key) {
                None => {
                    item_typs.insert(key, Value::String(type_name));
                }
                Some(item) => {
                    if !item.as_str().unwrap().is_empty() {
                        return;
                    }
                    item_typs.insert(key, Value::String(type_name));
                }
            }
        };
    }

    ///初始化typs中字段的类型
    pub fn init_typs(&mut self) {
        let mut typs_list: Vec<(String, String, String)> = vec![];
        for (index, value) in self.config.iter() {
            let mut csv_list: Vec<Vec<String>> = vec![];
            let path =
                self.config_path.to_string() + &value.get("table_name").unwrap().as_str().unwrap();
            let csv_buf = std::fs::File::open(path.clone()).unwrap();
            let mut rdr = csv::ReaderBuilder::new()
                .has_headers(false)
                .comment(Some(b'#'))
                .from_reader(csv_buf);
            for result in rdr.records() {
                let mut list: Vec<String> = vec![];
                match result {
                    Err(_) => {
                        println!("文件,{},解析失败", &path);
                        break;
                    }
                    Ok(record) => {
                        record.iter().for_each(|item| {
                            list.push(String::from(item));
                        });
                        csv_list.push(list.clone());
                    }
                }
            }
            let mut csv_to_list: Vec<(String, Vec<String>)> = vec![];
            for i in 0..csv_list.len() {
                if i == 0 {
                    for item in &csv_list[i] {
                        csv_to_list.push((item.clone(), vec![]));
                    }
                } else {
                    for j in 0..csv_list[i].len() {
                        csv_to_list[j].1.push(csv_list[i][j].clone());
                    }
                }
            }
            csv_to_list.iter().for_each(|item| {
                typs_list.push((index.clone(), item.0.clone(), get_type(item.1.clone())));
            })
        }

        for item in typs_list {
            self.push_config_types(item.0, item.1, item.2);
        }
    }

    ///将配置转换为json字符串
    pub fn to_json_string(&self) -> String {
        let json_str = serde_json::to_string_pretty(&self).unwrap();
        json_str
    }
}

fn get_json_str(path: &String) -> String {
    //判断 是否存在这个文件
    if !std::path::Path::new(path).exists() {
        return "".to_string();
    }

    let json_buf = std::fs::File::open(path).unwrap();
    let mut json_rdr = std::io::BufReader::new(json_buf);
    let mut json_str = String::new();
    json_rdr.read_to_string(&mut json_str).unwrap();
    json_str
}

/// 根据字符串判断它的类型
/// 目前只能推断number 其他人工推断吧TAT
fn get_type(value: Vec<String>) -> String {
    if value.len() == 0 {
        return "".into();
    }
    let mut is_number = true;
    for item in &value {
        //通过正则表达式判断是否是数字
        let re = Regex::new(r"^\d+(\.\d+)?$").unwrap();
        if !re.is_match(item.as_str()) {
            is_number = false;
            break;
        }
    }
    if is_number {
        return "number".into();
    }
    "".into()
}
